package com.ridu.project.beshid.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ridu.project.beshid.api.*;
import com.ridu.project.beshid.config.Global;
import com.ridu.project.beshid.config.GlobalConfiguration;
import com.ridu.project.beshid.entity.*;
import com.ridu.project.beshid.entity.JifenEntity;
import com.ridu.project.beshid.repository.*;
import com.ridu.project.beshid.service.JifenReqService;
import com.ridu.project.beshid.service.JifenService;
import com.ridu.project.beshid.utils.DateUtil;
import com.ridu.project.beshid.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by user on 2017/10/18.
 */
@Service
@Slf4j
public class JifenServiceImpl implements JifenService {

    @Autowired
    private JifenRepository repository;
    @Autowired
    private JifenReqRepository jifenReqRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private JifenReqService jifenReqService;
    @Autowired
    JifenAdminStreamRepository jifenAdminStreamRepository;
    @Autowired
    RestService restService;
    @Autowired
    private GlobalConfiguration globalConfiguration;
    @Autowired
    private JifenStreamRepository jifenStreamRepository;

    @Override
    public JifenEntity findByMobile(String mobile) {
        return repository.findByMobile(mobile);
    }

    @Override
    public JifenEntity findByUsername(String username) {
        return repository.findByUsername(username);
    }

    @Override
    public GeneralResponse getJifensAuditList(int currentPage, int pageSize, String status) {
        return getJifensAuditList(currentPage, pageSize, null, null, null, null, status);
    }

    @Override
    public GeneralResponse getJifensAuditList(int currentPage, int pageSize, String startTime, String endTime, String username, String platform, String status) {
        GeneralResponse<JifenReq> response = new GeneralResponse<>();
        try {
            if (currentPage == 0) {
                currentPage = 1;
            }
            if (pageSize == 0) {
                pageSize = Global.DEFAULT_PAGE_SIZE;
            }
            Sort sort = new Sort(Sort.Direction.DESC, "id");
            Pageable pageable = new PageRequest(currentPage - 1, pageSize, sort);
            Page<JifenReqEntity> page = jifenReqRepository.findAll(new Specification<JifenReqEntity>() {
                @Override
                public Predicate toPredicate(Root<JifenReqEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    List<Predicate> queryPredicates = new ArrayList<>();
                    if (!StringUtil.format(startTime).equals("") ||
                            !StringUtil.format(endTime).equals("")) {
                        Date s = DateUtil.parse(startTime);
                        Date e = DateUtil.parse(endTime + " 23:59:59");
                        if (!StringUtil.format(startTime).equals("") &&
                                !StringUtil.format(endTime).equals("")) {
                            queryPredicates.add(cb.between(root.<Date>get("dateCreated"), s, e));
                        } else if (StringUtil.format(startTime).equals("")) {
                            queryPredicates.add(cb.lessThanOrEqualTo(root.<Date>get("dateCreated"), e));
                        } else if (StringUtil.format(endTime).equals("")) {
                            queryPredicates.add(cb.greaterThanOrEqualTo(root.<Date>get("dateCreated"), s));
                        }
                    }
                    if (StringUtils.isNotBlank(username)) {
                        queryPredicates.add(cb.equal(root.<Long>get("owner").<String>get("beshId"), username));
                    } else {
                        queryPredicates.add(cb.isNull(root.<Long>get("user_req")));
                    }
                    if (StringUtils.isNotBlank(platform)) {
                        queryPredicates.add(cb.equal(root.<String>get("platform"), platform));
                    }
                    if (StringUtils.isBlank(status)) {
                        queryPredicates.add(cb.or(cb.isNull(root.<String>get("status")), cb.equal(root.<String>get("status"), "")));
                    }
                    query.where(queryPredicates.toArray(new Predicate[0]));
                    return null;
                }
            }, pageable);
            List<JifenReqEntity> dataList = page.getContent();
            List<JifenReq> jifens = new ArrayList<>();
            if (CollectionUtils.size(dataList) > 0) {
                dataList.stream().forEach(jifenEntity -> {
                    JifenReq req = new JifenReq();
                    BeanUtils.copyProperties(jifenEntity, req);
                    if (jifenEntity.getOwner() != null) {
                        req.setMobile(jifenEntity.getUser().getUsername());
                        req.setPlatform(jifenEntity.getUser().getPlatform());
                    }
                    jifens.add(req);
                });
            }
            response.setStatus(Status.SUCCESS);
            response.setRows(jifens);
            response.setTotal(page.getTotalElements());
        } catch (Exception e) {
            response.setStatus(Status.FAILED);
            response.setMessage(e.getMessage());
            log.error("error", e);
        }
        return response;
    }

    @Override
    public GeneralResponse sent(String mobiles) {
        GeneralResponse response = new GeneralResponse();
        try {
            if (StringUtil.isEmpty(mobiles)) {
                throw new Exception("参数错误");
            }
            List<JifenReqEntity> jifenReqEntities = jifenReqService.findByMobiles(mobiles);
            if (CollectionUtils.size(jifenReqEntities) > 0) {
                jifenReqEntities.stream().forEach(jifenReq -> {
                    if (jifenReq.getOwner() != null) {
                        JifenEntity entity = findByMobile(jifenReq.getOwner().getBeshId());
                        UserEntity u = jifenReq.getUser_req();
                        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
                        map.add("jifen", jifenReq.getReq_jifen().toString());
                        map.add("userId", jifenReq.getOwner().getBeshId());
                        String resultJson = null;
                        if (entity == null) {
                            map.add("total", jifenReq.getReq_jifen().toString());
                            try {
                                resultJson = (String) restService.postForEntity(globalConfiguration.getEthereumUrl() + "jifen/save", map);
                                JSONObject obj = JSONObject.parseObject(resultJson);
                                if (obj.getString("status").equals("SUCCESS")) {
                                    entity = new JifenEntity();
                                    entity.setJifen(jifenReq.getReq_jifen().toString());
                                    entity.setOwner(jifenReq.getOwner());
                                    entity.setTotal(jifenReq.getReq_jifen().toString());
                                    entity.setTransactionHash(JSONObject.parseObject(obj.getString("data")).getString("transactionHash"));
                                    repository.save(entity);
                                    saveStream(jifenReq.getReq_jifen().toString(), jifenReq.getReq_jifen().toString()
                                            , jifenReq.getOwner(), "批量审核积分", entity.getTransactionHash());
                                    u.setJifen(jifenReq.getReq_jifen().intValue());
                                } else {
                                    response.setMessage(obj.getString("message"));
                                    response.setStatus(Status.FAILED);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                                log.error(e.getMessage());
                            }
                        } else {
                            BigDecimal cur = new BigDecimal(StringUtil.format(entity.getJifen()).equals("") ? "0" : entity.getJifen());
                            cur = cur.add(jifenReq.getReq_jifen());
                            map.add("total", cur.toString());
                            try {
                                resultJson = (String) restService.postForEntity(globalConfiguration.getEthereumUrl() + "jifen/save", map);
                                JSONObject obj = JSONObject.parseObject(resultJson);
                                if (obj.getString("status").equals("SUCCESS")) {
                                    entity.setTotal(cur.toString());
                                    entity.setTransactionHash(JSONObject.parseObject(obj.getString("data")).getString("transactionHash"));
                                    repository.saveAndFlush(entity);
                                    saveStream(jifenReq.getReq_jifen().toString(), cur.toString()
                                            , jifenReq.getOwner(), "批量审核积分", entity.getTransactionHash());
                                    u.setJifen(cur.intValue());
                                } else {
                                    response.setMessage(obj.getString("message"));
                                    response.setStatus(Status.FAILED);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                                log.error(e.getMessage());
                            }
                        }
                        userRepository.saveAndFlush(u);
                        jifenReq.setStatus("OK");
                        jifenReqRepository.save(jifenReq);
                    }
                });
            }
        } catch (Exception e) {
            response.setMessage(e.getMessage());
            response.setStatus(Status.FAILED);
        }
        return response;
    }

    private void saveStream(String jifen, String total, BeshUserEntity owner, String description, String transactionHash) throws Exception{
        JifenStreamEntity entity = new JifenStreamEntity();
        entity.setJifen(jifen);
        entity.setTotal(total);
        entity.setDescription(description);
        entity.setOwner(owner);
        entity.setTransactionHash(transactionHash);
        jifenStreamRepository.save(entity);
    }

    @Override
    public GeneralResponse getStream(int currentPage, int pageSize, String startTime, String endTime, String category) {
        GeneralResponse response = new GeneralResponse();
        try {
            if (currentPage == 0) {
                currentPage = 1;
            }
            if (pageSize == 0) {
                pageSize = Global.DEFAULT_PAGE_SIZE;
            }
            Sort sort = new Sort(Sort.Direction.DESC, "id");
            Pageable pageable = new PageRequest(currentPage - 1, pageSize, sort);
            Page<JifenAdminStreamEntity> page = jifenAdminStreamRepository.findAll(new Specification<JifenAdminStreamEntity>() {
                @Override
                public Predicate toPredicate(Root<JifenAdminStreamEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    List<Predicate> queryPredicates = new ArrayList<>();
                    if (!StringUtil.format(startTime).equals("") ||
                            !StringUtil.format(endTime).equals("")) {
                        Date s = DateUtil.parse(startTime);
                        Date e = DateUtil.parse(endTime + " 23:59:59");
                        if (!StringUtil.format(startTime).equals("") &&
                                !StringUtil.format(endTime).equals("")) {
                            queryPredicates.add(cb.between(root.<Date>get("dateCreated"), s, e));
                        } else if (StringUtil.format(startTime).equals("")) {
                            queryPredicates.add(cb.lessThanOrEqualTo(root.<Date>get("dateCreated"), e));
                        } else if (StringUtil.format(endTime).equals("")) {
                            queryPredicates.add(cb.greaterThanOrEqualTo(root.<Date>get("dateCreated"), s));
                        }
                    }
                    if (StringUtils.isNotBlank(category)) {
                        queryPredicates.add(cb.equal(root.<String>get("category"), category));
                    }
                    query.where(queryPredicates.toArray(new Predicate[0]));
                    return null;
                }
            }, pageable);
            List<JifenAdminStreamEntity> dataList = page.getContent();
            List<JifenAdminStream> jifens = new ArrayList<>();
            if (CollectionUtils.size(dataList) > 0) {
                dataList.stream().forEach(jifenEntity -> {
                    JifenAdminStream req = new JifenAdminStream();
                    BeanUtils.copyProperties(jifenEntity, req);
                    if (jifenEntity.getOwner() != null) {
                        req.setUsername(jifenEntity.getOwner().getUsername());
                    }
                    jifens.add(req);
                });
            }
            response.setStatus(Status.SUCCESS);
            response.setRows(jifens);
            response.setTotal(page.getTotalElements());
        } catch (Exception e) {
            response.setMessage(e.getMessage());
            response.setStatus(Status.FAILED);
        }
        return response;
    }

    @Override
    public GeneralResponse getDetail(String transactionHash) {
        GeneralResponse<TransactionReceipt> response = new GeneralResponse<>();
        Map<String, String> map = new HashMap<>();
        map.put("transactionHash", transactionHash);
        TransactionReceipt receipt =  (TransactionReceipt)restService.getForObject(globalConfiguration.getEthereumUrl() + "jifen/getReceiptByHash", map, TransactionReceipt.class);
        response.setStatus(Status.SUCCESS);
        response.setData(receipt);
        return response;
    }
}
